package imp

import (
	sqlc "bgs/db/sqlc"
	brandDistributeRequestGrpc "bgs/grpc/gen/service/brand_distribute_request"
	"bgs/grpc/gen/shared/message"
	"bgs/grpc/imp/enums"
	"bgs/util"
	"bytes"
	"context"
	"database/sql"
	"encoding/json"
	"fmt"
	"strings"
	"time"
)

/****************************************************************************************/
/*                               brand_distribute_request entity of helper                 */
/****************************************************************************************/

func transformBrandDistributeRequestEntityToPb(BrandDistributeRequest sqlc.BrandDistributeRequest) *brandDistributeRequestGrpc.BrandDistributeRequestEntity {
	return &brandDistributeRequestGrpc.BrandDistributeRequestEntity{
		Id:          BrandDistributeRequest.ID,
		BrandId:     BrandDistributeRequest.BrandID,
		UserId:      BrandDistributeRequest.UserID,
		Requested:   sqlc.GoTimeToPBTimestamp(BrandDistributeRequest.Requested),
		Audited:     sqlc.GoTimeToPBTimestamp(BrandDistributeRequest.Audited.Time),
		ApplyFields: string(BrandDistributeRequest.ApplyFields),
		AuditResult: BrandDistributeRequest.AuditResult,
	}
}

/****************************************************************************************/
/*                               brand_distribute_request entity of cmd                    */
/****************************************************************************************/

// ApplyBrandDistributeRequest 申请品牌分销请求
func (s *BrandAPIService) ApplyBrandDistributeRequest(ctx context.Context, req *brandDistributeRequestGrpc.ApplyBrandDistributeRequestRequest) (res *brandDistributeRequestGrpc.ApplyBrandDistributeRequestResponse, err error) {
	slog := s.NewContextLogger(ctx)
	slog.Infof("brand_distribute_requestImp->ApplyBrandDistributeRequest:%v", req)

	res = &brandDistributeRequestGrpc.ApplyBrandDistributeRequestResponse{
		OpRet: &message.OperationResult{
			Success: true,
			Code:    0,
		},
	}
	q := s.dao.Q
	// 1 判断分销设置
	brandDistributeEndorsement, sqlErr := q.GetBrandDistributeEndorsementByBrandID(ctx, req.BrandId)
	if sqlErr != nil {
		if sql.ErrNoRows != sqlErr {
			err = sqlErr
		} else {
			err = fmt.Errorf("品牌未开启招募分销员 brandID:%d", req.BrandId)
		}
		return
	}
	// 查到分销设置
	if !brandDistributeEndorsement.IsOpen {
		err = fmt.Errorf("品牌关闭了招募分销员 brandID:%d", req.BrandId)
		return
	}

	if brandDistributeEndorsement.UserStratified == string(enums.UserStratificationConsumer) {
		// 检查消息记录
		// 临时
		err = fmt.Errorf("未实现对于用户的品牌最低消费金额计算 userID:%d", req.BrandId)
		return
	}

	if !brandDistributeEndorsement.NeedApplyInfo {
		err = fmt.Errorf("没有任何申请信息不可能存在%d", req.BrandId)
		return
	}

	var oApplyFields map[string]string
	if decodeErr := json.NewDecoder(strings.NewReader(req.ApplyFields)).Decode(&oApplyFields); decodeErr != nil {
		err = fmt.Errorf("无法解析申请信息: %v", decodeErr)
		return
	}
	fields := brandDistributeEndorsement.ApplyInfoFields
	for _, field := range fields {
		if oApplyFields[field] == "" {
			err = fmt.Errorf("缺少申请信息: %s", field)
			return
		}
	}

	// 2 判断是否申请用户已经是品牌的分销员
	brandDistributor, sqlErr := q.GetBrandDistributorByUserIDAndBrandID(ctx, sqlc.GetBrandDistributorByUserIDAndBrandIDParams{
		UserID:  req.UserId,
		BrandID: req.BrandId,
	})

	if sqlErr != nil {
		if sql.ErrNoRows != sqlErr {
			err = sqlErr
			return
		}
		slog.Infof("还不是品牌分销员,继续")
	} else {
		// 查到分销员了
		if brandDistributor.Status == string(enums.RecordStatusNormal) {
			err = fmt.Errorf("已经是品牌分销员了userID:%d,brandID:%d", req.UserId, req.BrandId)
			return
		}
	}

	// 没找到分销员或者分销员处于作废状态,需要继续寻找是否有相同的申请记录
	pendingRequestCount, sqlErr := s.dao.Q.CountPendingBrandDistributeRequestByBrandIDAndUserID(ctx,
		sqlc.CountPendingBrandDistributeRequestByBrandIDAndUserIDParams{
			UserID:  req.UserId,
			BrandID: req.BrandId,
		},
	)
	if sqlErr != nil {
		err = sqlErr
		return
	}
	slog.Infof("寻找是否有相同的申请记录=>%d", pendingRequestCount)

	if pendingRequestCount > 0 {
		err = fmt.Errorf("已经存在分销员申请记录userID:%d,brandID:%d", req.UserId, req.BrandId)
		return
	}
	var needSendNotify bool
	var brandDistributeRequest sqlc.BrandDistributeRequest
	err = s.dao.NewTxRunner().SqlcExecTx(ctx, func(q *sqlc.Queries) (err error) {
		// 3 创建分销申请,如果是自动审核,设置品牌分销关系
		brandDistributeRequest, err = q.CreateBrandDistributeRequest(ctx, sqlc.CreateBrandDistributeRequestParams{
			BrandID:     req.BrandId,
			UserID:      req.UserId,
			ApplyFields: []byte(req.ApplyFields),
			Audited:     util.IfThenElse(brandDistributeEndorsement.IsAutoApproved, sqlc.NTimeFromTime(time.Now()), sql.NullTime{}).(sql.NullTime),
			AuditResult: string(util.IfThenElse(brandDistributeEndorsement.IsAutoApproved, enums.AuditResultApproved, enums.AuditResultPending).(enums.EnumAuditResult)),
		})
		if err != nil {
			return err
		}
		slog.Infof("创建分销申请成功=>", brandDistributeRequest.ID)
		// 此处brandDistributeRequest.AuditResult只有pending和approved两种结果
		userID := brandDistributeRequest.UserID
		brandID := brandDistributeRequest.BrandID
		if brandDistributeRequest.AuditResult == string(enums.AuditResultApproved) {
			// 插入/更新品牌分销关系
			_, err = q.UpsertBrandDistributor(ctx, sqlc.UpsertBrandDistributorParams{
				UserID:    userID,
				BrandID:   brandID,
				AliasName: oApplyFields[string(sqlc.EmBrandDistributionEndorseApplyFieldNickName)],
				Became:    time.Now(),
			})
			if err != nil {
				return err
			}

			err = s.brandService.UpdateBrandStatDistributorCountSinceUpsertBrandDistributor(ctx, q, brandID)
			if err != nil {
				return
			}
			slog.Infof("s2 更新品牌统计的distributor_count ok")

			needSendNotify = true
		} else {
			err = s.brandService.UpdateBrandStatDistributeRequestCountSinceCreateBrandDistributePendingRequest(ctx, q, brandID)
			if err != nil {
				return
			}
			slog.Infof("s2 更新品牌统计的distribute_request_to_audit_count ok")
		}
		return
	})
	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}

	if needSendNotify {
		notifyParam, genErr := s.brandService.GenDistributeRequestAuditedNotifyMessage(ctx, s.dao.Q, brandDistributeRequest.ID)
		if genErr != nil {
			slog.Errorf("ApplyBrandDistributeRequest 生成分销员审核结果消息失败:%s", genErr.Error())
			// 不影响主流程因此不赋值给err
		}
		sendErr := s.wxpMinaService.SendNotify(ctx, &notifyParam)
		if sendErr != nil {
			slog.Errorf("ApplyBrandDistributeRequest 发送mina分销员审核结果提醒失败:%s", sendErr.Error())
		}
	}
	res.BrandDistributeRequest = transformBrandDistributeRequestEntityToPb(brandDistributeRequest)
	return
}

// AuditBrandDistributeRequest 审核品牌分销请求
func (s *BrandAPIService) AuditBrandDistributeRequest(ctx context.Context, req *brandDistributeRequestGrpc.AuditBrandDistributeRequestRequest) (res *brandDistributeRequestGrpc.AuditBrandDistributeRequestResponse, err error) {
	slog := s.NewContextLogger(ctx)
	slog.Infof("brand_distribute_requestImp->AuditBrandDistributeRequest:%v", req)
	res = &brandDistributeRequestGrpc.AuditBrandDistributeRequestResponse{
		OpRet: &message.OperationResult{
			Success: true,
			Code:    0,
		},
	}
	if req.AuditResult == string(enums.AuditResultPending) {
		err = fmt.Errorf("无效的审核结果:%s", req.AuditResult)
		return
	}

	var needSendNotify bool
	var brandDistributeRequest sqlc.BrandDistributeRequest
	err = s.dao.NewTxRunner().SqlcExecTx(ctx, func(q *sqlc.Queries) (err error) {

		arg := sqlc.UpdateBrandDistributeRequestParams{
			ID:          req.Id,
			Audited:     sqlc.NTimeFromTime(sqlc.PBTimestampToGoTime(req.Audited)),
			AuditResult: req.AuditResult,
		}
		brandDistributeRequest, err = q.UpdateBrandDistributeRequest(ctx, arg)
		if err != nil {
			return err
		}
		
		var oApplyFields map[sqlc.EmBrandDistributionEndorseApplyField]string
		if decodeErr := json.NewDecoder(bytes.NewReader(brandDistributeRequest.ApplyFields)).Decode(&oApplyFields); err != nil {
			err = fmt.Errorf("无法解析申请信息: %s", decodeErr)
			return
		}

		if brandDistributeRequest.AuditResult == string(enums.AuditResultApproved) {
			// 插入/更新品牌分销关系
			userID := brandDistributeRequest.UserID
			brandID := brandDistributeRequest.BrandID
			_, err = q.UpsertBrandDistributor(ctx, sqlc.UpsertBrandDistributorParams{
				UserID:    userID,
				BrandID:   brandID,
				AliasName: oApplyFields[sqlc.EmBrandDistributionEndorseApplyFieldNickName],
				Became:    time.Now(),
			})
			if err != nil {
				return err
			}

			err = s.brandService.UpdateBrandStatDistributorCountSinceUpsertBrandDistributor(ctx, q, brandID)
			if err != nil {
				return
			}
			slog.Infof("s2 更新品牌统计的distributor_count ok")

		} else if brandDistributeRequest.AuditResult == string(enums.AuditResultApproved) {
			// 拒绝,暂时什么都不做
			slog.Infof("审核分销员拒绝")
		}
		needSendNotify = true
		return
	})
	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}
	if needSendNotify {
		notifyParam, genErr := s.brandService.GenDistributeRequestAuditedNotifyMessage(ctx, s.dao.Q, brandDistributeRequest.ID)
		if genErr != nil {
			slog.Errorf("AuditBrandDistributeRequest 生成分销员审核结果消息失败:%s", genErr.Error())
			// 不影响主流程因此不赋值给err
		}
		sendErr := s.wxpMinaService.SendNotify(ctx, &notifyParam)
		if sendErr != nil {
			slog.Errorf("AuditBrandDistributeRequest 发送mina分销员审核结果提醒失败:%s", sendErr.Error())
		}
	}
	res.BrandDistributeRequest = transformBrandDistributeRequestEntityToPb(brandDistributeRequest)
	return
}

/****************************************************************************************/
/*                               brand_distribute_request entity of query                  */
/****************************************************************************************/

// GetBrandDistributeRequest 获取单个品牌分销请求
func (s *BrandAPIService) GetBrandDistributeRequest(ctx context.Context, req *brandDistributeRequestGrpc.GetBrandDistributeRequestRequest) (res *brandDistributeRequestGrpc.GetBrandDistributeRequestResponse, err error) {
	slog := s.NewContextLogger(ctx)
	slog.Infof("brand_distribute_requestImp->GetBrandDistributeRequest:%v", req)
	res = &brandDistributeRequestGrpc.GetBrandDistributeRequestResponse{
		OpRet: &message.OperationResult{
			Success: true,
			Code:    0,
		},
	}
	brandDistributeRequest, err := s.dao.Q.GetBrandDistributeRequest(ctx, req.Id)
	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}
	res.BrandDistributeRequest = transformBrandDistributeRequestEntityToPb(brandDistributeRequest)
	return
}

// GetBrandDistributeRequestByBrandIDAndUserID 根据品牌ID和用户ID获取最新的分销请求
func (s *BrandAPIService) GetBrandDistributeRequestByBrandIDAndUserID(ctx context.Context, req *brandDistributeRequestGrpc.GetBrandDistributeRequestByBrandIDAndUserIDRequest) (res *brandDistributeRequestGrpc.GetBrandDistributeRequestByBrandIDAndUserIDResponse, err error) {
	slog := s.NewContextLogger(ctx)
	slog.Infof("brand_distribute_requestImp->GetBrandDistributeRequestByBrandIDAndUserID:%v", req)
	res = &brandDistributeRequestGrpc.GetBrandDistributeRequestByBrandIDAndUserIDResponse{
		OpRet: &message.OperationResult{
			Success: true,
			Code:    0,
		},
	}
	q := s.dao.Q
	userID := req.UserId
	brandID := req.BrandId
	
	brandDistributeRequest, sqlErr := q.GetBrandDistributeRequestByBrandIDAndUserID(ctx, sqlc.GetBrandDistributeRequestByBrandIDAndUserIDParams{
		BrandID: brandID,
		UserID:  userID,
	})

	if sqlErr != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    util.Int32IfThenElse(sql.ErrNoRows == sqlErr, 404, 400),
			Msg:     sqlErr.Error(),
		}
		return
	}
	res.BrandDistributeRequest = transformBrandDistributeRequestEntityToPb(brandDistributeRequest)

	if brandDistributeRequest.AuditResult == string(sqlc.EmAuditResultApproved) {
		distributorPtr, getErr := s.brandService.GetDistributorPtrByUserIDAndBrandID(ctx, q, userID, brandID)
		if getErr != nil {
			err = getErr
			return
		}
		res.DistributorId = distributorPtr.ID
	}
	
	return
}

/****************************************************************************************/
/*                               brand_distribute_requestJoins entity of helper            */
/****************************************************************************************/

func transformBrandDistributeRequestWithUserInfoEntityToPb(o sqlc.ListBrandDistributeRequestWithUserInfosByBrandIDAndAuditResultsRow) *brandDistributeRequestGrpc.BrandDistributeRequestWithUserInfoEntity {
	return &brandDistributeRequestGrpc.BrandDistributeRequestWithUserInfoEntity{
		Id:          o.ID,
		BrandId:     o.BrandID,
		UserId:      o.UserID,
		Requested:   sqlc.GoTimeToPBTimestamp(o.Requested),
		Audited:     sqlc.GoTimeToPBTimestamp(o.Audited.Time),
		ApplyFields: string(o.ApplyFields),
		AuditResult: o.AuditResult,
		UserPic:     o.UserPic.String,
	}
}

func mapBrandDistributeRequestWithUserInfoEntityToPb(list []sqlc.ListBrandDistributeRequestWithUserInfosByBrandIDAndAuditResultsRow, f func(sqlc.ListBrandDistributeRequestWithUserInfosByBrandIDAndAuditResultsRow) *brandDistributeRequestGrpc.BrandDistributeRequestWithUserInfoEntity) []*brandDistributeRequestGrpc.BrandDistributeRequestWithUserInfoEntity {
	r := make([]*brandDistributeRequestGrpc.BrandDistributeRequestWithUserInfoEntity, len(list))
	for i, item := range list {
		r[i] = f(item)
	}
	return r
}

/****************************************************************************************/
/*                               brand_distribute_requestJoins entity of query                  */
/****************************************************************************************/

// ListBrandDistributeRequestWithUserInfosByBrandID  根据品牌ID获取分销请求+用户信息
func (s *BrandAPIService) ListBrandDistributeRequestWithUserInfosByBrandID(ctx context.Context, req *brandDistributeRequestGrpc.ListBrandDistributeRequestWithUserInfosByBrandIDRequest) (res *brandDistributeRequestGrpc.ListBrandDistributeRequestWithUserInfosByBrandIDResponse, err error) {
	slog := s.NewContextLogger(ctx)
	slog.Infof("brand_distribute_requestImp->ListBrandDistributeRequestWithUserInfosByBrandID:%v", req)

	res = &brandDistributeRequestGrpc.ListBrandDistributeRequestWithUserInfosByBrandIDResponse{
		OpRet: &message.OperationResult{
			Success: true,
			Code:    0,
		},
	}

	q := s.dao.Q
	brandID := req.BrandId
	auditResults := req.AuditResults

	total, err := q.CountBrandDistributeRequestWithUserInfosByBrandIDAndAuditResults(ctx, sqlc.CountBrandDistributeRequestWithUserInfosByBrandIDAndAuditResultsParams{
		Created:      sqlc.PBTimestampToGoTime(req.Ts),
		BrandID:      brandID,
		AuditResults: auditResults,
	})
	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}
	if total == 0 {
		// 不用继续调用listfunc
		return
	}

	brandDistributeRequests, err := q.ListBrandDistributeRequestWithUserInfosByBrandIDAndAuditResults(ctx, sqlc.ListBrandDistributeRequestWithUserInfosByBrandIDAndAuditResultsParams{
		Limit:        req.Limit,
		Offset:       req.Offset,
		Created:      sqlc.PBTimestampToGoTime(req.Ts),
		BrandID:      req.BrandId,
		AuditResults: auditResults,
	})
	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}
	res.Total = total
	res.BrandDistributeRequestWithUserInfos = mapBrandDistributeRequestWithUserInfoEntityToPb(brandDistributeRequests, transformBrandDistributeRequestWithUserInfoEntityToPb)
	return
}
